/**
 ** 译码的顶级模块
 ** 模块的输出不能连接到reg，只能用wire，否则会报下面的错
 ** cannot be driven by primitives or continuous assignment.
**/

module ID (
    input wire clk,                    //时钟信号
    input wire rst,                    //复位信号（暂无使用）
    input wire [31:0] pc_in,           //当前输入的PC
    input wire [31:0] now_inst,        //当前要执行的指令
    input wire wb_reg_wr_ctrl,         //来自于写回阶段的寄存器写入控制信号
    input wire [31:0] wb_reg_wr_data,  //来自于写回阶段的寄存器写入的内容
    input wire [4:0] wb_reg_wr_no,     //来自写回阶段的寄存器的编号
    input wire [31:0] pre_exe_result,  //来自运行阶段的前一条指令的运算结果(旁路前递)
    input wire [31:0] pre_exe_inst,    //来自运行阶段的前一条指令，用于比较寄存器号
    input wire [31:0] pre_mem_result,  //来自访存阶段的前前一条指令的运算结果(旁路前递)
    input wire [31:0] pre_mem_inst,    //来自访存阶段的前前一条指令，用于比较寄存器号
    output wire rf_wr_en,              //寄存器写信号
    output wire [1:0] rf_wr_sel,       //寄存器选择信号
    output wire [3:0] alu_ctrl,        //运算器的控制信号
    output wire [2:0] dm_rd_ctrl,      //数据存储器的读取控制信号
    output wire [1:0] dm_wr_ctrl,      //数据存储器的写入控制信号
    output reg [31:0] src_a,           //运算器的操作数A
    output reg [31:0] src_b           //运算器的操作数B
);
    wire [31:0] imm_out;  //填充过后的立即数
    wire [2:0] imm_ctrl;  //立即数填充模式的控制信号
    wire [4:0] reg_a1;    //读or写的寄存器号
    wire [4:0] reg_a2;
    wire [4:0] reg_a3;
    wire [31:0] reg_rs;   //寄存器堆中读取出来的内容
    wire [31:0] reg_rt;
    wire [31:0] reg_rs_final;  //综合旁路分支技术的寄存器值
    wire [31:0] reg_rt_final;
    wire alu_a_sel;            //输入选择信号，参见文档说明
    wire alu_b_sel;

    //从指令中取出寄存器号
    assign reg_a1 = now_inst[19:15];
    assign reg_a2 = now_inst[24:20];
    assign reg_a3 = now_inst[11:7];
    //寄存器是否替换成前递技术的标记
    wire rs_en;
    wire rt_en;

    /**
        当rs_en或者rt_en为1时，表示当前指令的运算寄存器是前面指令的结果寄存器，例如：
        addi r4 r4 41
        addi r5 r5 41
        add r6 r4 r5
        第三条指令运算时，前两条指令尚未写回，所以需要加入旁路前递器ByPass，提前把之前指令的运算结果往前递
        故在下面的代码中，当rs_en或者rt_en为1时，将输出的寄存器值替换成前递模块传过来的值
    **/
    always @(*) begin
        //alu_a_sel 说明见文档
        if (alu_a_sel==0) begin
            src_a = pc_in;
        end

        if(alu_a_sel==1) begin
            if (rs_en==1) begin 
                src_a = reg_rs_final;
            end
            else begin
                src_a = reg_rs;
            end
        end

        //alu_b_sel 说明见文档
        if (alu_b_sel==0) begin
            if (rt_en==1) begin
                src_b = reg_rt_final;
            end
            else begin
                src_b = reg_rt;
            end
        end

        if(alu_b_sel==1) begin
            src_b = imm_out;
        end
    end

    //实例化一个控制器
    commonControl ctrl1(.now_inst(now_inst), .pc(pc_in), .rf_wr_en(rf_wr_en), .rf_wr_sel(rf_wr_sel), .alu_a_sel(alu_a_sel), .alu_b_sel(alu_b_sel), .alu_ctrl(alu_ctrl), .dm_rd_ctrl(dm_rd_ctrl), .dm_wr_ctrl(dm_wr_ctrl), .imm_ctrl(imm_ctrl));  

    //实例化立即数拓展器
    immPadding imm1(.imm_ctrl(imm_ctrl), .now_inst(now_inst), .imm_out(imm_out));  

    //实例化寄存器堆
    registers reg1(.clk(clk), .rst(rst), .now_a1(reg_a1), .now_a2(reg_a2), .now_a3(wb_reg_wr_no), .write_in(wb_reg_wr_data), .write_en(wb_reg_wr_ctrl), .now_rs(reg_rs), .now_rt(reg_rt));

    //实例化旁路前递器
    byPass by2(.alu_a_in(reg_rs), .alu_b_in(reg_rt), .pre_exe_result(pre_exe_result), .pre_mem_result(pre_mem_result), .inst(now_inst), .ex_inst(pre_exe_inst), .mem_inst(pre_mem_inst), .alu_a_out(reg_rs_final), .alu_b_out(reg_rt_final), .rs_en(rs_en), .rt_en(rt_en));
endmodule